package com.lovesher.payment.service.plugin.alipay;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.lovesher.payment.common.enums.EnumAlipayTradeStatus;
import com.lovesher.payment.common.enums.NotifyMethod;
import com.lovesher.payment.common.enums.PayStatus;
import com.lovesher.payment.common.enums.PayType;
import com.lovesher.payment.common.resposity.bean.AccountRechargeDTO;
import com.lovesher.payment.common.resposity.bean.PaymentSerial;
import com.lovesher.payment.common.resposity.bean.PluginConfig;
import com.lovesher.payment.common.resposity.bean.PluginConfigAttribute;
import com.lovesher.payment.service.resposity.bean.PaymentInterface;
import com.lovesher.payment.service.resposity.dao.PaymentDao;
import com.lovesher.payment.service.resposity.dao.PaymentSerialDao;
import com.lovesher.payment.service.resposity.mapper.PluginConfigAttributeMapper;

/**
 * @Title: AliPayDirectPlugin.java
 * 
 * @Package net.showcoo.plugin.alipay
 * 
 * @Prject: yun-service
 * 
 * @Description: 支付宝支付插件
 * 
 * 
 * @version V1.0
 */
@Component("aliPayDirectPlugin")
public class AliPayDirectPlugin extends PaymentInterface {

	private static Log log = LogFactory.getLog(AliPayDirectPlugin.class);

	@Resource
	private PluginConfigAttributeMapper pluginConfigAttributeMapper;
	@Resource
	private PaymentDao paymentDao;
	@Resource
	private PaymentSerialDao paymentSerialDao;

	@Override
	public String getName() {
		return "支付宝网页即时到账";
	}

	@Override
	public String getVersion() {
		return "1.0";
	}

	@Override
	public String getAuthor() {
		return "hyf";
	}

	/**
	 * 获取网址
	 * 
	 * @return 网址
	 */
	@Override
	public String getSiteUrl() {
		return "https://doc.open.alipay.com";
	}

	/**
	 * 获取请求URL
	 * 
	 * @return 请求URL
	 */
	@Override
	public String getRequestUrl() {
		return "https://mapi.alipay.com/gateway.do";
	}

	/**
	 * 获取请求方法
	 * 
	 * @return 请求方法
	 */
	@Override
	public RequestMethod getRequestMethod() {
		return RequestMethod.post;
	}

	/**
	 * 获取请求字符编码
	 * 
	 * @return 请求字符编码
	 */
	@Override
	public String getRequestCharset() {
		return "UTF-8";
	}

	/**
	 * 使用 Map按key进行排序
	 * 
	 * @param map
	 * @return
	 */
	public static Map<String, Object> sortMapByKey(Map<String, Object> map) {
		if (map == null || map.isEmpty()) {
			return null;
		}

		Map<String, Object> sortMap = new TreeMap<String, Object>();

		sortMap.putAll(map);

		return sortMap;
	}

	/**
	 * 获取请求参数
	 * 
	 * @param sn
	 *            编号
	 * @param description
	 *            描述
	 * @param request
	 *            httpServletRequest
	 * @return 请求参数
	 */
	@Override
	public Map<String, String> getParameterMap(AccountRechargeDTO accountRechargeDTO, String serialSn) {
		PluginConfig pluginConfig = getPluginConfig();
		// 数据库中获取支付相关参数
		Map<String, Object> pluginConfigMap = getPluginConfigMap(pluginConfig);
		
		Map<String, String> resultMap = new HashMap<String, String>();

		log.info("【订单:" + accountRechargeDTO.getTradeNo() + "userId" + accountRechargeDTO.getUserId() + "】开始封装参数...");

		// 调用的接口名，无需修改
		resultMap.put("service", "create_direct_pay_by_user");

		// 合作身份者ID，签约账号
		resultMap.put("partner", pluginConfigMap.get("partner").toString());

		// 收款支付宝用户ID。如果该值为空，则默认为商户签约账号对应的支付宝用户ID
		resultMap.put("seller_id", pluginConfigMap.get("seller_id").toString());

		// 字符编码格式
		resultMap.put("input_charset", this.getRequestCharset());

		// 签名方式
		resultMap.put("sign_type", pluginConfigMap.get("sign_type").toString());

		resultMap.put("notify_url", super.getNotifyUrl(serialSn, accountRechargeDTO.getUserId(), NotifyMethod.async,
				PayType.valueOf(accountRechargeDTO.getType())));// 接收支付宝支付异步通知回调地址

		resultMap.put("return_url", super.getNotifyUrl(serialSn, accountRechargeDTO.getUserId(), NotifyMethod.sync,
				PayType.valueOf(accountRechargeDTO.getType())));// 接收支付宝支付同步通知回调地址

		// 商品的标题/交易标题/订单标题/订单关键字等。
		resultMap.put("subject", "盈米科技");

		// 商户网站唯一订单号
		resultMap.put("out_trade_no", accountRechargeDTO.getTradeNo());

		// 支付类型 ，无需修改
		resultMap.put("payment_type", "1");

		// 订单总金额
		resultMap.put("total_fee", accountRechargeDTO.getMoney().toString());

		// 构造签名字符串
		String sign = this.createSign(resultMap, pluginConfigMap);
		// 构造签名字符串
		resultMap.put("sign", sign);
		resultMap.put("req_url", getRequestUrl());
		log.info("【订单:" + accountRechargeDTO.getTradeNo() + "userId" + accountRechargeDTO.getUserId() + "】封装参数成功...");

		return resultMap;
	}

	/**   
	 * @Title: getPluginConfigMap   
	 * @param pluginConfig
	 * @return     
	 * @throws   
	 */  
	private Map<String, Object> getPluginConfigMap(PluginConfig pluginConfig) {
		Map<String, Object> pluginConfigMap = new HashMap<String, Object>();
		List<PluginConfigAttribute> pluginConfigAttributes = pluginConfigAttributeMapper
				.findByPluginId(pluginConfig.getId());
		for (int i = 0; i < pluginConfigAttributes.size(); i++) {
			PluginConfigAttribute pluginConfigAttribute = pluginConfigAttributes.get(i);
			pluginConfigMap.put(pluginConfigAttribute.getName(), pluginConfigAttribute.getAttributes());
		}
		return pluginConfigMap;
	}
	
	/**
	 * 构造签名
	 * 
	 * @param params
	 * @param pluginConfigMap 
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	public String createSign(Map<String, String> params, Map<String, Object> pluginConfigMap) {
		return AliRSA.sign(params,
				pluginConfigMap.get("private_key").toString(), this.getRequestCharset());
	}

	/**
	 * 验证通知是否合法
	 * 
	 * @param sn
	 *            编号
	 * @param notifyMethod
	 *            通知方法
	 * @param request
	 *            httpServletRequest
	 * @return 通知是否合法
	 */
	@SuppressWarnings("rawtypes")
	@Override
	public Map<String, Object> verifyNotify(String sn, NotifyMethod notifyMethod, HttpServletRequest request,
			PaymentSerial paymentSerial) {

		PluginConfig pluginConfig = getPluginConfig();
		Map<String, Object> pluginConfigMap = getPluginConfigMap(pluginConfig);
		String sign_type = pluginConfigMap.get("sign_type").toString();
		String partner = pluginConfigMap.get("partner").toString();
		String alipay_public_key = pluginConfigMap.get("alipay_public_key").toString();
		
		Map<String, Object> returnNotify = new HashMap<String, Object>();
		log.info("【支付宝订单:" + request.getParameter("out_trade_no") + "】异步回调开始...");
		// 通知校验ID
		String notify_id = request.getParameter("notify_id");
		// 获取远程服务器ATN结果,验证返回URL
		String veNoid = AlipayNotify.verifyResponse(notify_id, partner);
		if (veNoid.equals("invalid")) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空");
			log.error("命令参数不对 出现这个错误，请检测返回处理中partner和key是否为空");
			return returnNotify;
		} else if (veNoid.equals("false")) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟");
			log.error("请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟");
			return returnNotify;
		}

		// 签名
		String sign = request.getParameter("sign");

		Map<String, Object> velMap = new HashMap<String, Object>();
		Enumeration enu = request.getParameterNames();

		while (enu.hasMoreElements()) {
			String paraName = (String) enu.nextElement();
			velMap.put(paraName, request.getParameter(paraName));

		}

		if (!AlipayNotify.getSignVeryfy(velMap, sign, sign_type, alipay_public_key)) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "参数验签失败");
			log.error(new StringBuffer("参数验签失败").append(JSONObject.toJSONString(velMap))
					.append(",sign:").append(sign).append(",sign_type:").append(sign_type)
					.append(",alipay_public_key:").append(alipay_public_key));
			return returnNotify;
		}

		String out_trade_no = request.getParameter("out_trade_no");
		// 商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号
		if (!sn.equals(out_trade_no)) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "不是商户系统中创建的订单号");
			log.error("不是商户系统中创建的订单号");
			return returnNotify;
		}

		// 订单金额
		String total_amount = request.getParameter("total_fee");

		if (new BigDecimal(total_amount).compareTo(paymentSerial.getMoney()) != 0) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "不为该订单的实际金额");
			log.error("不为该订单的实际金额");
			return returnNotify;
		}

		// 卖家支付宝用户号
		String seller_id = request.getParameter("seller_id");
		if (!pluginConfigMap.get("seller_id").equals(seller_id)) {
			returnNotify.put("success", false);
			returnNotify.put("returnText", "不为这笔单据的对应的操作方");
			return returnNotify;
		}

		returnNotify.put("success", true);
		returnNotify.put("returnText", "验签成功");
		return returnNotify;
	}

	/**
	 * 获取通知返回消息
	 * 
	 * @param sn
	 *            编号
	 * @param notifyMethod
	 *            通知方法
	 * @param request
	 *            httpServletRequest
	 * @return 通知返回消息
	 */
	@Override
	public String getNotifyMessage(String sn, NotifyMethod notifyMethod, HttpServletRequest request) {
		if (notifyMethod == NotifyMethod.async) {
			return "success";
		}
		return "failure";
	}

	/**
	 * 获取超时时间
	 * 
	 * @return 超时时间
	 */
	@Override
	public Integer getTimeout() {
		return 21600;
	}

	/**
	 * 充值支付回调验证成功处理方法
	 * 
	 * @param request
	 */
	@Override
	public void paySucess(PaymentSerial paymentSerial, String returnText, PayStatus payStatus,
			HttpServletRequest request) {
		String trade_status = request.getParameter("trade_status");
		if(null != trade_status && trade_status.equals(EnumAlipayTradeStatus.TRADE_SUCCESS.getName()) && payStatus == PayStatus.SUCCESS){
			payStatus = PayStatus.SUCCESS;
		}else if(payStatus == PayStatus.SUCCESS){
			payStatus = PayStatus.FAILURE;
		}
		paymentDao.handle(paymentSerial, returnText, payStatus);
	}

	@Override
	public Boolean queryOrderResult(PaymentSerial paymentSerial) {
		// TODO Auto-generated method stub
		return null;
	}

}
